package cn.fornever.dbdoc.util;

import cn.fornever.dbdoc.entity.BaseEntity;
import cn.fornever.dbdoc.entity.MyColumnInfo;
import org.apache.commons.lang3.StringUtils;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DbDocUtil {
    private static Pattern p = Pattern.compile("_(\\w)");

    /**
     * 转驼峰命名
     * @param str   要转驼峰的字符串
     * @return  驼峰字符串
     */
    public static String toCamel(String str) {
        String result = str.toLowerCase();
        final StringBuffer sb = new StringBuffer();
        Matcher m = p.matcher(result);
        while (m.find()) {
            //正则之前的字符和被替换的字符
            m.appendReplacement(sb, m.group(1).toUpperCase());
        }
        m.appendTail(sb);
        return sb.toString();
    }

    /**
     * 转驼峰命名
     * @param str   要转驼峰的字符串
     * @param initialToUpperCase 首字母是否大写
     * @return      驼峰字符串
     */
    public static String toCamel(String str, Boolean initialToUpperCase) {
        return initialToUpperCase ? initialToUpperCase(toCamel(str)) : toCamel(str);
    }

    public static Object getValue(String key, Map<String, Object> data) {
        Object val = data.get(key);
        if (val instanceof Timestamp) {
            return LocalDateTime.ofInstant(Instant.ofEpochMilli(((Timestamp) data.get(key)).getTime()), ZoneId.systemDefault()).format(LocalDateTimeUtils.DATE_TIME_FORMATTER_YMD_HMS);
        }
        return val;
    }

    public static Object getValue(String key, Map<String, Object> data, Object defValue) {
        return data.get(key) == null ? defValue : getValue(key, data);
    }

    public static Object getApiSuccessValue(String javaType, String key, Map<String, Object> data) {
        Object value = data.get(key);
        if (value == null) {
            return "null";
        }
        if ("String".equals(javaType) || "Date".equals(javaType)) {
            return "\"" + value + "\"";
        }
        return value;
    }

    public static String initialToUpperCase(String str) {
        char[] charArray = str.toCharArray();
        if (charArray[0] >= 'a' && charArray[0] <= 'z') {
            charArray[0] = (char) (charArray[0] - 32);
        }
        return new String(charArray);
    }

    public static String initialToLowerCase(String str) {
        char[] charArray = str.toCharArray();
        if (charArray[0] >= 'A' && charArray[0] <= 'Z') {
            charArray[0] = (char) (charArray[0] + 32);
        }
        return new String(charArray);
    }

    public static String getCurrentDate() {
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return dtf2.format(LocalDateTime.now());
    }

    public static String getCurrentDateTime() {
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return dtf2.format(LocalDateTime.now());
    }

    public static void setBaseInfo(BaseEntity entity,String basePackage) {

        if (entity.getBasePackage() == null) {
            entity.setBasePackage(basePackage + "." + getSubPackage(entity.getTab().getTableAlias()));
        }
        entity.setBaseInstanceName(DbDocUtil.toCamel(entity.getTab().getTableAlias()));
        entity.setBaseClassName(DbDocUtil.initialToUpperCase(entity.getBaseInstanceName()));
        entity.setCurrentDate(getCurrentDate());
        Map<String, Object> funcs = new HashMap<>(8);
        funcs.put("DbDocUtil", FreeMarkerUtil.getStaticModel(DbDocUtil.class));
        funcs.put("StringUtils", FreeMarkerUtil.getStaticModel(StringUtils.class));
        entity.setFuncs(funcs);
    }

    public static List<MyColumnInfo> getQoInfo(List<MyColumnInfo> colList) {
        List<MyColumnInfo> qoInfoList = new ArrayList<>();
        MyColumnInfo qo;
        for (MyColumnInfo colInfo : colList) {
            if (colInfo.getEntityProName().endsWith("Tp")
                    || colInfo.getEntityProName().endsWith("Type")
                    || colInfo.getEntityProName().endsWith("Status")
                    || colInfo.getColumnSize() <= 4) {
                // xx类型
                qoInfoList.add(setQoInfo(colInfo, "List", "List<" + colInfo.getJavaType() + ">", "(数组)"));
            } else if ("String".equalsIgnoreCase(colInfo.getJavaType())) {
                if (colInfo.getEntityProName().endsWith("Cd") || colInfo.getEntityProName().endsWith("Id")) {
                    // xx编码
                    qoInfoList.add(setQoInfo(colInfo, "List", "List<" + colInfo.getJavaType() + ">", "(数组)"));
                    qoInfoList.add(setQoInfo(colInfo, "", colInfo.getJavaType(), ""));
                } else if (colInfo.getEntityProName().endsWith("Ym")) {
                    // 设站年月,忽略
                } else {
                    qoInfoList.add(setQoInfo(colInfo, "", colInfo.getJavaType(), ""));
                }
            } else if ("Date".equalsIgnoreCase(colInfo.getJavaType()) || "LocalDateTime".equalsIgnoreCase(colInfo.getJavaType())) {
                // 时间字段
                qoInfoList.add(setQoInfo(colInfo, "BgTm", colInfo.getJavaType(), "(开始时间)"));
                qoInfoList.add(setQoInfo(colInfo, "EdTm", colInfo.getJavaType(), "(结束时间)"));
            } else if ("Double".equalsIgnoreCase(colInfo.getJavaType()) || "Integer".equalsIgnoreCase(colInfo.getJavaType())
                    || "Integer".equalsIgnoreCase(colInfo.getJavaType())) {
                // 数值类型
                qoInfoList.add(setQoInfo(colInfo, "Min", colInfo.getJavaType(), "(最小)"));
                qoInfoList.add(setQoInfo(colInfo, "Max", colInfo.getJavaType(), "(最大)"));
            } else if (colInfo.getJdbcType().contains("LOB")
                    || "SDO_GEOMETRY".equals(colInfo.getDbType())
                    || "UROWID".equals(colInfo.getDbType())
                    || "UNDEFINED".equals(colInfo.getDbType())
                    ) {
                // CLOB、BLOB、NCLOB、NBLOB、SDO_GEOMETRY等字段
                System.out.println("CLOB/BLOB/SDO_GEOMETRY/OTHER COLUMN:" + colInfo.getTableName() + "." + colInfo.getColumnName());
            } else {
                // TODO  WQ_NMISP_D.CODMN:dbTypenull:jdbcTypeDECIMAL WQ_NMISP_D.CODCR:dbTypenull:jdbcTypeDECIMAL
                System.out.println(colInfo.getTableName() + "." + colInfo.getColumnName() + ":dbType" + colInfo.getDbType() + ":jdbcType" + colInfo.getJdbcType());
            }
        }
        return qoInfoList;
    }

    private static MyColumnInfo setQoInfo(MyColumnInfo colInfo, String proName, String javaType, String remarkPrefix) {
        MyColumnInfo qo = new MyColumnInfo();
        qo.setEntityProName(colInfo.getEntityProName() + proName);
        qo.setJavaType(javaType);
        qo.setJdbcType(colInfo.getJdbcType());
        qo.setColumnSize(colInfo.getColumnSize());
        qo.setColumnName(colInfo.getColumnName());
        qo.setRemarks(remarkPrefix + colInfo.getRemarks());
        return qo;
    }

    public static Object getDefaultValue(MyColumnInfo columnInfo) {
        if (StringUtils.isNotEmpty(columnInfo.getColumnDef())) {
            return columnInfo.getColumnDef();
        }
        Object requestParamDef;
        switch (columnInfo.getJavaType()) {
            case "String": {
                requestParamDef = columnInfo.getNullable() == 1 ? "\"\"" : ("\"此项不能为空,允许的最大长度为" + columnInfo.getColumnSize() + "\"");
                break;
            }
            case "Double": {
                requestParamDef = 0;
                break;
            }
            case "Integer": {
                requestParamDef = 0;
                break;
            }
            case "Date": {
                requestParamDef = "\"" + DbDocUtil.getCurrentDateTime() + "\"";
                break;
            }
            default: {
                requestParamDef = null;
                break;
            }
        }
        return requestParamDef;
    }

    private static String getSubPackage(String tableName) {
        String result;
        String[] arr = tableName.split("_");
        result = (keyWordReplace(arr[0]) + "." + keyWordReplace(arr[1])).toLowerCase();
        return result;
    }

    /**
     * 避免java关键字
     *
     * @param word
     * @return
     */
    private static String keyWordReplace(String word) {
        switch (word.toLowerCase()) {
            case "int": {
                return word + "x";
            }
            case "char": {
                return word + "x";
            }
            case "do": {
                return word + "x";
            }
            default: {
                return word;
            }
        }
    }

    public static String getDirectory(String tableName) {
        return getSubPackage(tableName).replaceAll("\\.", "\\\\");
    }

    public static String getPath(String tableName) {
        String result;
        String[] arr = tableName.split("_");
        if ("WR".equals(arr[0]) || "WQ".equals(arr[0])) {
            // WR 水资源管理数据库 + 水质
            if ("_B".equals(arr[arr.length - 1])) {

            }
        } else if ("GEO".equals(arr[0]) || "SQL".equals(arr[0])) {
            // GEO_α_XT 空间信息类
            // GEO_表标识分类，固定字符，代表空间数据库。α表标识的主体标识。
            // XT 表标识分类后缀，固定字符，代表数据比例尺，如
            // 1：1万数据比例尺表示为1T，1：5万数据表示为5T，1：25万数据应表示成25T，1：100万表示为100T，1：400万表示为400

            // SPL_Z_C_X 空间关系类
            // SPL_空间关系类分类码，固定字符，用于区分业务关系类。Z主导要素标识。C从属要素标识。X关系类型标识。
            // 表7-1 空间类型关系编码表
            // X 关系类型
            // 1 流向关系
            // 2 包含关系
            // 3 压盖关系
            // 4 衔接关系
            // 5 相交关系
            // 6 跨越关系
            // 7 依附关系
        } else if ("REL".equals(arr[0])) {
            // 业务关系类表
//            result = "rel";
//            for(int i = 1;i<arr.length;i++){
//                result+="/"+arr[i];
//            }
        }else if ("WREM".equals(arr[0])) {
            // 业务关系类表
//            result = "rel";
//            for(int i = 1;i<arr.length;i++){
//                result+="/"+arr[i];
//            }
            tableName = tableName.replaceAll("WREM","GENERATE");
        }

        return tableName.toLowerCase().replaceAll("_", "/");
    }


    public static String getApiGroup(){
        return null;
    }

    public static void main(String[] args) {
        System.out.println(toCamel("WR_WPC_M"));
        System.out.println(initialToLowerCase("AAA"));
        System.out.println(initialToUpperCase("aAA"));
    }
}
